#include <cmath>
#include <complex>
#include <cstdlib>

#include "evaluator_utils.h"

constexpr uint64_t FOO_MAX_LEN = UINT64_MAX; // 定义最大长度常量
// ----------------------------------------------------------------------------------
//   RANDOM REAL AND COMPLEX NUMBERS
// ----------------------------------------------------------------------------------

double EvaluatorUtils::RandomReal(double bound)
{
//    return (double)rand() / (RAND_MAX)*bound;
    static std::mt19937 gen(std::random_device{}());
    std::uniform_real_distribution<double> dis(0.0, bound);
    return dis(gen);
}

complex<double> EvaluatorUtils::RandomComplex(double bound)
{
    complex<double> res;
    res.real(RandomReal(bound));
    res.imag(RandomReal(bound));
    return res;
}

complex<double> EvaluatorUtils::RandomCircle(double angleBound)
{
    double angle = RandomReal(angleBound);
    complex<double> res;
    res.real(cos(angle * 2 * M_PI));
    res.imag(sin(angle * 2 * M_PI));
    return res;
}

double *EvaluatorUtils::RandomRealArray(long size, double bound)
{
    if (size == 0 || size > FOO_MAX_LEN) {
        throw std::runtime_error("Invalid value for size.");
    }
    double *res = new double[size];
    for (long i = 0; i < size; i++) {
        res[i] = RandomReal(bound);
    }
    return res;
}

complex<double> *EvaluatorUtils::RandomComplexArray(long size, double bound)
{
    if (size == 0 || size > FOO_MAX_LEN) {
        throw std::runtime_error("Invalid value for size.");
    }
    complex<double> *res = new complex<double>[size];
    for (long i = 0; i < size; i++) {
        res[i] = RandomComplex(bound);
    }
    return res;
}

complex<double> *EvaluatorUtils::RandomCircleArray(long size, double bound)
{
    if (size == 0 || size > FOO_MAX_LEN) {
        throw std::runtime_error("Invalid value for size.");
    }
    complex<double> *res = new complex<double>[size];
    for (long i = 0; i < size; i++) {
        res[i] = RandomCircle(bound);
    }
    return res;
}

void EvaluatorUtils::LeftRotateAndEqual(complex<double> *vals, const long size, const long rotSize)
{
    if (size == 0) {
        throw std::runtime_error("Divisor mod by zero is not allowed.");
    }
    long remRotSize = rotSize % size;
    if (remRotSize != 0) {
        long divisor = Gcd(remRotSize, size);
        if (divisor == 0) {
            throw std::runtime_error("Divisor mod by zero is not allowed.");
        }
        long steps = size / divisor;
        for (long i = 0; i < divisor; i++) {
            complex<double> tmp = vals[i];
            long idx = i;
            for (long j = 0; j < steps - 1; j++) {
                vals[idx] = vals[(idx + remRotSize) % size];
                idx = (idx + remRotSize) % size;
            }
            vals[idx] = tmp;
        }
    }
}

void EvaluatorUtils::RightRotateAndEqual(complex<double> *vals, const long size, const long rotSize)
{
    if (size == 0) {
        throw std::runtime_error("Divisor mod by zero is not allowed.");
    }
    long remRotSize = rotSize % size;
    long leftRemRotSize = (size - remRotSize) % size;
    LeftRotateAndEqual(vals, size, leftRemRotSize);
}
